package redis

import (
	"errors"
	"strconv"
	"time"

	"github.com/go-redis/redis"
)

// 定义常量
const (
	// 一周时间秒表示
	oneWeekInSeconds = 7 * 24 * 3600
	// 每一票占432分（86400/200）--> 两百张赞成票可以给你的帖子续一天
	scorePreVote = 432
)

var (
	ErrVoteTimeExpire = errors.New("投票时间已过！")
	ErrVoteRepeated   = errors.New("不能重复投票！")
)

// 创建帖子
func CreatePost(postID, communityID int64) (err error) {
	// 3. （1. 2 3步必须同时成功）所以利用管道事务执行
	pipeline := rdb.TxPipeline()
	// 1. 将帖子的创建时间存入redis
	pipeline.ZAdd(getRedisKey(KeyPostTimeZSet), redis.Z{
		Score:  float64(time.Now().Unix()),
		Member: postID,
	})
	// 2. 将帖子的初始分数存入redis，默认的就是创建的时间戳
	pipeline.ZAdd(getRedisKey(KeyPostScoreZSet), redis.Z{
		Score:  float64(0),
		Member: postID,
	})
	// 3. 将帖子id加入对应社区
	ckey := getRedisKey(KeyCommunitySetPF + strconv.FormatInt(communityID, 10))
	pipeline.SAdd(ckey, postID)
	_, err = pipeline.Exec()
	return err
}

func VoteForPost(userID, postID string, dir float64) (err error) {
	// 1. 判断投票限制, 超过一周不允许投票
	// 取帖子发布时间
	postTime := rdb.ZScore(getRedisKey(KeyPostTimeZSet), postID).Val()
	if float64(time.Now().Unix())-postTime > oneWeekInSeconds*4 {
		return ErrVoteTimeExpire
	}
	// 第二步后一个操作和第三步也要放到管道事务里去，都要同时执行成功
	pipeline := rdb.Pipeline()
	// 2. 更新帖子的分数
	// 先查询当前用户的投票记录
	pre := rdb.ZScore(getRedisKey(KeyPostVotedZSetPF+postID), userID).Val()
	// 如果两次操作一致，不允许！就是一个人投多次票
	if pre == dir {
		return ErrVoteRepeated
	}
	// 根据上一步的操作的值和当前操作值的比较，来判断出是加还是减，也就是符号位
	//var op float64
	//if dir > pre {
	//	op = 1
	//} else {
	//	op = -1
	//}
	// 计算两次投票的差值绝对值
	//diff := math.Abs(pre - dir)
	// 更新redis中的字段值
	postScore := rdb.ZScore(getRedisKey(KeyPostScoreZSet), postID).Val()
	//if !(op*diff*scorePreVote < 0 && -1*op*diff*scorePreVote > postScore) {
	//	pipeline.ZIncrBy(getRedisKey(KeyPostScoreZSet), op*diff*scorePreVote, postID)
	//}
	if dir == -1 {
		if scorePreVote > postScore {

		} else {
			pipeline.ZIncrBy(getRedisKey(KeyPostScoreZSet), -1*scorePreVote, postID)
		}
	} else if dir == 1 {
		pipeline.ZIncrBy(getRedisKey(KeyPostScoreZSet), scorePreVote, postID)
	}
	// 3. 记录用户为该帖子投票的动作，如果为 0，取消投票。 否则记录一下
	if dir == 0 {
		pipeline.ZRem(getRedisKey(KeyPostVotedZSetPF+postID), userID)
	} else {
		pipeline.ZAdd(getRedisKey(KeyPostVotedZSetPF+postID), redis.Z{
			Score:  dir,
			Member: userID,
		})
	}
	_, err = pipeline.Exec()
	return err
}
